home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / contrib / port.isc / pico / os_isc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-17  |  22.4 KB  |  1,083 lines

  1. /*
  2.  * Program:    Operating system dependent routines - Ultrix 4.1
  3.  *
  4.  * Author:    Michael Seibel
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: mikes@cac.washington.edu
  11.  *
  12.  * Date:    6 Jan 1992
  13.  * Last Edited:    11 May 1992
  14.  *
  15.  * Copyright 1991 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  * Notes:
  35.  *
  36.  * SGI IRIX 4.0.1 port by:
  37.  *       johnb@edge.cis.mcmaster.ca,  2 April 1992
  38.  *
  39.  * Dynix/PTX port by:
  40.  *       Donn Cave, UCS/UW, 15 April 1992
  41.  *
  42.  *
  43.  */
  44.  
  45. #include     <stdio.h>
  46. #include    <errno.h>
  47. #include    <setjmp.h>
  48. #include    <time.h>
  49. #include    <pwd.h>
  50.  
  51. #include    "osdep.h"
  52. #include    "estruct.h"
  53. #include        "edef.h"
  54. #include        "pico.h"
  55.  
  56. #ifdef    POSIX
  57. #include    <termios.h>
  58.  
  59. struct termios nstate,
  60.         ostate;
  61. #else
  62. #if    defined(sv3) || defined(sgi) ||  defined(ISC)
  63. #include    <termio.h>
  64.  
  65. struct termio nstate,
  66.               ostate;
  67.  
  68. #else
  69. struct  sgttyb  ostate;          /* saved tty state */
  70. struct  sgttyb  nstate;          /* values for editor mode */
  71. struct tchars    otchars;    /* Saved terminal special character set */
  72. struct tchars    ntchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  73.                 /* A lot of nothing */
  74. #endif    /* sv3 || sgi */
  75. #endif    /* POSIX */
  76.  
  77. extern    int rtfrmshell();    /* return from suspended shell */
  78.  
  79. jmp_buf    alrm_state;        /* stack env to handle SIGALRM */
  80.  
  81.  
  82. #if    defined(nxt) || defined(aix) || defined(POSIX)
  83. #define    SIGTYPE    void
  84. #else
  85. #define    SIGTYPE int
  86. #endif
  87.  
  88. SIGTYPE    do_hup_signal();
  89. SIGTYPE    do_alarm_signal();
  90. #ifdef    TIOCGWINSZ
  91. SIGTYPE    winch_handler();
  92. #endif
  93.  
  94. #ifdef    ISC
  95. SIGTYPE    do_int_signal();
  96. void    (*save_sigint)();
  97. #endif
  98.  
  99.  
  100. /*
  101.  * This function is called once to set up the terminal device streams.
  102.  */
  103. ttopen()
  104. {
  105.     if(Pmaster == NULL){
  106. #ifdef    POSIX
  107.         tcgetattr (0, &ostate);
  108.         tcgetattr (0, &nstate);
  109.         nstate.c_lflag &= ~(ISIG | ICANON | ECHO);
  110.         nstate.c_iflag &= ~ICRNL;
  111.         nstate.c_oflag &= ~(ONLCR | OPOST);
  112.         nstate.c_cc[VMIN] = 1;
  113.         nstate.c_cc[VTIME] = 0;
  114.         tcsetattr (0, TCSADRAIN, &nstate);
  115. #else
  116. #if    defined(sv3) || defined(sgi) || defined (ISC)
  117.         (void) ioctl(0, TCGETA, &ostate);
  118.         (void) ioctl(0, TCGETA, &nstate);    /** again! **/
  119.  
  120.         nstate.c_lflag &= ~(ICANON | ISIG | ECHO);    /* noecho raw mode  */
  121.         nstate.c_oflag &= ~(OPOST | ONLCR);
  122.         nstate.c_iflag &= ~INLCR;
  123.         
  124.         nstate.c_cc[VMIN] = '\01';  /* minimum # of chars to queue  */
  125.         nstate.c_cc[VTIME] = '\0'; /* minimum time to wait for input */
  126.         (void) ioctl(0, TCSETA, &nstate);
  127. #else
  128.         ioctl(0, TIOCGETP, &ostate);    /* save old state */
  129.         ioctl(0, TIOCGETP, &nstate);    /* get base of new state */
  130.         nstate.sg_flags |= RAW;
  131.         nstate.sg_flags &= ~(ECHO|CRMOD);    /* no echo for now... */
  132.         ioctl(0, TIOCSETP, &nstate);     /* set mode */
  133.         
  134.         ioctl(0, TIOCGETC, &otchars);     /* Save old characters */
  135.         ioctl(0, TIOCSETC, &ntchars);     /* put new character into K */
  136. #endif    /* sv3 */
  137. #endif    /* POSIX */
  138.     }
  139.  
  140.     signal(SIGHUP, (SIGTYPE *)do_hup_signal); /* deal with SIGHUP */
  141.     signal(SIGALRM, (SIGTYPE *)do_alarm_signal); /* timer for new mail */
  142. #ifdef    TIOCGWINSZ
  143.         signal(SIGWINCH, (SIGTYPE *)winch_handler); /* window size changes */
  144. #endif
  145. #ifndef    sv3
  146.     signal(SIGTSTP, (SIGTYPE *)SIG_DFL);    /* set signals so we can */
  147.     signal(SIGCONT, (SIGTYPE *)rtfrmshell);    /* suspend & restart emacs */
  148. #endif
  149. }
  150.  
  151.  
  152.  
  153. /*
  154.  * This function gets called just before we go back home to the command
  155.  * interpreter.
  156.  */
  157. ttclose()
  158. {
  159.     if(Pmaster){
  160.     signal(SIGHUP, SIG_DFL);
  161.     signal(SIGALRM, SIG_DFL);
  162. #ifndef    sv3
  163.     signal(SIGCONT, SIG_DFL);
  164. #endif
  165. #ifdef    TIOCGWINSZ
  166.     signal(SIGWINCH, SIG_DFL);
  167. #endif
  168.     }
  169.     else{
  170. #ifdef    POSIX
  171.     tcsetattr (0, TCSADRAIN, &ostate);
  172. #else
  173. #if    defined(sv3) || defined(sgi) || defined(ISC)
  174.         ioctl(0, TCSETA, &ostate);
  175. #else
  176.     ioctl(0, TIOCSETP, &ostate);
  177.     ioctl(0, TIOCSETC, &otchars);
  178. #endif    /* sv3 || sgi */
  179. #endif    /* POSIX */
  180.     }
  181. #ifdef ISC
  182.     ioctl(0, TCSETAW, &ostate);    /* set old state */
  183. #endif
  184. }
  185.  
  186.  
  187. /*
  188.  * Write a character to the display. 
  189.  */
  190. ttputc(c)
  191. {
  192.     putc(c, stdout);
  193. }
  194.  
  195.  
  196. /*
  197.  * Flush terminal buffer. Does real work where the terminal output is buffered
  198.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  199.  */
  200. ttflush()
  201. {
  202.         fflush(stdout);
  203. }
  204.  
  205. /*
  206.  * Read a character from the terminal, performing no editing and doing no echo
  207.  * at all.
  208.  */
  209. ttgetc()
  210. {
  211.     register int c;
  212.  
  213.     if((c = fgetc(stdin)) == EOF){
  214.     if(errno == EINTR)        /* only one that might be OK */
  215.       return(NODATA);
  216.     kill(getpid(), SIGHUP);        /* the only honorable thing to do */
  217.     }
  218.     else
  219.       return(c & 0xff);
  220. }
  221.  
  222.  
  223. #if    TYPEAH
  224. /* typahead:    Check to see if any characters are already in the
  225.  *        keyboard buffer
  226.  */
  227. typahead()
  228. {
  229.     int x;    /* holds # of pending chars */
  230.  
  231.     return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x);
  232. }
  233. #endif
  234.  
  235.  
  236. /*
  237.  * Read in a key.
  238.  * Do the standard keyboard preprocessing. Convert the keys to the internal
  239.  * character set.  Resolves escape sequences and returns no-op if global
  240.  * timeout value exceeded.
  241.  */
  242. GetKey()
  243. {
  244.     int    c;
  245.  
  246.     if(timeout){
  247.         if(setjmp(alrm_state) == 0){
  248.         alarm((unsigned)timeout);
  249.         errno = 0;
  250.         c = (*term.t_getchar)();
  251.         if(errno == EINTR)
  252.           c = NODATA;
  253.         }
  254.         else
  255.           c = NODATA;         /* alarm went off so go back */
  256.  
  257.         alarm(0);            /* shut off the alarm */
  258.         if(c == NODATA)
  259.           return(c);
  260.     }
  261.     else{
  262.         c = (*term.t_getchar)();
  263.     }
  264.  
  265.     if (c == METACH) {                      /* Apply M- prefix      */
  266.         int status;
  267.         
  268.         /*
  269.          * this code should intercept special keypad keys
  270.          */
  271.  
  272.         switch(status = kbseq(&c)){
  273.           case 0 :     /* no dice */
  274.             return(c);
  275.           case  K_PAD_UP        :
  276.           case  K_PAD_DOWN        :
  277.           case  K_PAD_RIGHT        :
  278.           case  K_PAD_LEFT        :
  279.           case  K_PAD_PREVPAGE    :
  280.           case  K_PAD_NEXTPAGE    :
  281.           case  K_PAD_HOME        :
  282.             return(status);
  283.           case F1  :
  284.           case F2  :
  285.           case F3  :
  286.           case F4  :
  287.           case F5  :
  288.           case F6  :
  289.           case F7  :
  290.           case F8  :
  291.           case F9  :
  292.           case F10 :
  293.           case F11 :
  294.           case F12 :
  295.             return(status);
  296.           case BADESC :
  297.           default :             /* punt the whole thing    */
  298.             (*term.t_beep)();
  299.             break;
  300.         }
  301.         }
  302.  
  303.         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  304.           c = CTRL | (c+'@');
  305.  
  306.         return (c);
  307.  
  308. }
  309.  
  310.  
  311.  
  312. /* kbseq - looks at an escape sequence coming from the keyboard and 
  313.  *         compares it to a trie of known keyboard escape sequences, and
  314.  *         performs the function bound to the escape sequence.
  315.  * 
  316.  *         returns: BADESC, the escaped function, or 0 if not found.
  317.  */
  318. kbseq(c)
  319. int    *c;
  320. {
  321.     register char    b;
  322.     register int    first = 1;
  323.     register struct    KBSTREE    *current = kpadseqs;
  324.  
  325.     if(kpadseqs == NULL)                /* bag it */
  326.         return(BADESC);
  327.     while(1){
  328.         *c = b = (*term.t_getchar)();
  329.  
  330.         while(current->value != b){
  331.             if(current->left == NULL){        /* NO MATCH */
  332.             if(first)
  333.               return(BADESC);
  334.             else
  335.               return(0);
  336.             }
  337.             current = current->left;
  338.         }
  339.  
  340.         if(current->down == NULL)        /* match!!!*/
  341.           return(current->func);
  342.         else
  343.           current = current->down;
  344.  
  345.         first = 0;
  346.     }
  347. }
  348.  
  349.  
  350.  
  351. /*
  352.  * This is code for a planned pine feature that isn't actually in use 
  353.  * yet.  It is an example of one possible way of implementing an alternate
  354.  * editor, but maybe not the final word on how it will be done.  
  355.  * It may be that we decide to make this a configuration option (thus 
  356.  * saving a very limited resource: control-key combinations.  We're 
  357.  * still considering these options...
  358.  */
  359. #include <sys/wait.h>
  360.  
  361.  
  362. /*
  363.  * alt_editor - fork off an alternate editor for mail message composition
  364.  */
  365. alt_editor(f, n)
  366. {
  367. #ifdef OLDWAY
  368.     char   eb[NLINE];
  369. #else
  370.     char   *eb;
  371. #endif
  372.     char   *fn;
  373.     char   *writetmp();
  374.     int       child, pid, done = 0;
  375.     long   l; 
  376. #if defined(POSIX) || defined(ISC)
  377.     int    stat;
  378. #else
  379.     union  wait stat;
  380. #endif
  381.     FILE   *p;
  382.  
  383. #ifdef OLDWAY
  384.     *eb = '\0';
  385. #endif
  386.  
  387.     if(Pmaster == NULL)
  388.       return;
  389.  
  390. #ifdef OLDWAY
  391.     while(!done){
  392.     /* which alternate editor */
  393.     switch(mlreply("Which alternate editor ? ", eb, NLINE, TRUE)){
  394.       case ABORT:
  395.         return(-1);
  396.       case HELPCH:
  397.         emlwrite("no alternate editor help yet");
  398.  
  399. /* take sleep and break out after there's help */
  400.         sleep(3);
  401.         break;
  402.       case (CTRL|'L'):
  403.         sgarbf = TRUE;
  404.         update();
  405.         break;
  406.       case TRUE:
  407.       case FALSE:                    /* does editor exist ? */
  408.         if(*eb== '\0'){                /* leave silently */
  409.         emlwrite("");
  410.         return(-1);
  411.         }
  412. #ifdef MAYBELATER
  413.         else if(*eb != '/'){
  414.         int status;
  415.         char *fp, *efp;
  416.  
  417.         if(*eb == '~'){
  418.             strcpy(s, "~");
  419.             fixpath(s, 1024);
  420.             strcat(s,"/");
  421.             strcat(eb,"/");
  422.         }
  423.         else if((fp=getenv("PATH")) == NULL){
  424.             emlwrite("Can't find editor \"%s\"", eb);
  425.             return(-1);
  426.         }
  427. else
  428.  emlwrite("got path: %s",fp);
  429.         while(fp){
  430.             sprintf(s, "%s/%s", fp, eb);
  431.             if((status=fexist(eb, "x", &l)) != FIOSUC){
  432.             fioperr(status, eb);
  433.             return(-1);
  434.             }
  435.         }
  436.         }
  437. #endif
  438.         done++;
  439.         break;
  440.       default:
  441.         break;
  442.     }
  443.     }
  444. #else
  445.     if(Pmaster->alt_ed == NULL)
  446.       return;
  447.  
  448.     eb = Pmaster->alt_ed;
  449. #endif
  450.  
  451.     if((fn=writetmp(0, 1)) == NULL){    /* get temp file */
  452.     emlwrite("Problem writing temp file for alt editor");
  453.     return(-1);
  454.     }
  455.  
  456.     if(Pmaster)
  457.       (*Pmaster->raw_io)(0);        /* turn off raw mode */
  458.  
  459.     if(child=fork()){            /* wait for the child to finish */
  460.     while((pid=wait(&stat)) != child)
  461.       ;
  462.     }
  463.     else{                /* spawn editor */
  464.     if(execlp(eb, eb, fn, (char *) 0) < 0)
  465.       exit(1);
  466.     }
  467.  
  468.     if(Pmaster)
  469.       (*Pmaster->raw_io)(1);        /* turn on raw mode */
  470.  
  471.     /*
  472.      * replace edited text with new text 
  473.      */
  474.     curwp->w_bufp->b_flag &= ~BFCHG;    /* make sure it gets blasted */
  475.     bclear(curwp->w_bufp);        /* blast old text */
  476.     readin(fn, 0);            /* read new text */
  477.     unlink(fn);                /* blast temp file */
  478.  
  479.     ttopen();
  480.     refresh(0, 1);            /* redraw */
  481. }
  482.  
  483.  
  484.  
  485. /*
  486.  *  bktoshell - suspend and wait to be woken up
  487.  */
  488. bktoshell()        /* suspend MicroEMACS and wait to wake up */
  489. {
  490. #ifndef    sv3
  491.     int pid;
  492.     int rtfrmshell();
  493.     extern int vttidy();
  494.  
  495.         if(!(gmode&MDSSPD)){
  496.         emlwrite("\007Unknown command: ^Z");
  497.             return;
  498.     }
  499.  
  500.     if(Pmaster){
  501.         (*Pmaster->raw_io)(0);    /* actually in pine source */
  502.  
  503.         movecursor(term.t_nrow, 0);
  504.         printf("\n\n\nUse \"fg\" to return to Pine\n");
  505.  
  506.         signal(SIGTSTP,SIG_DFL);    /* set signals so that we can */
  507.         signal(SIGCONT, (SIGTYPE *)rtfrmshell); /* suspend & restart emacs */
  508.     }
  509.     else{
  510.         vttidy();
  511.     }
  512.  
  513.         movecursor(term.t_nrow, 0);
  514.         peeol();
  515.         (*term.t_flush)();
  516.  
  517.     pid = getpid();
  518.     kill(pid,SIGTSTP);
  519. #else
  520. #endif
  521. }
  522.  
  523.  
  524. /* 
  525.  * rtfrmshell - back from shell, fix modes and return
  526.  */
  527. rtfrmshell()
  528. {
  529. #ifndef    sv3
  530.         if(Pmaster){
  531.         signal(SIGCONT, SIG_DFL);
  532.         if(Pmaster)
  533.           (*Pmaster->raw_io)(1);        /* actually in pine source */
  534.         (*Pmaster->keybinit)(gmode&MDFKEY);    /* using f-keys? */
  535.     }
  536.  
  537.     ttopen();
  538.  
  539.     sgarbf = TRUE;
  540.     curwp->w_flag = WFHARD;
  541.     refresh();
  542. #else
  543. #endif
  544. }
  545.  
  546.  
  547.  
  548. /*
  549.  * do_alarm_signal - jump back in the stack to where we can handle this
  550.  */
  551. SIGTYPE do_alarm_signal()
  552. {
  553.     signal(SIGALRM, (SIGTYPE *)do_alarm_signal);
  554.     longjmp(alrm_state, 1);
  555. }
  556.  
  557. #ifdef ISC
  558. /*
  559.  * do_int_signal - jump back in the stack to where we can handle this
  560.  */
  561.  /*  I don't know how this works for other OS's!  Seems like a bug, no? */
  562.  
  563. SIGTYPE do_int_signal()
  564. {
  565. extern    jmp_buf    finstate;    /* stack environment to return codes [pico.c] */
  566.             /* This will handle SIGINT */
  567.  
  568.     if(0 /*for_pine*/){
  569.     signal(SIGINT, (SIGTYPE *)do_int_signal);
  570.     abort_composer(1,0);
  571.     }
  572. }
  573.  
  574. #endif
  575.  
  576. /*
  577.  * do_hup_signal - jump back in the stack to where we can handle this
  578.  */
  579. SIGTYPE do_hup_signal()
  580. {
  581.     extern  jmp_buf   got_hup;
  582.  
  583.     if(Pmaster){
  584.     signal(SIGHUP, (SIGTYPE *)do_hup_signal);
  585.     longjmp(got_hup, 1);
  586.     }
  587.     else{
  588.     /*
  589.      * if we've been interrupted and the buffer is changed,
  590.      * save it...
  591.      */
  592.     if(anycb() == TRUE){            /* time to save */
  593.         if(curbp->b_fname[0] == '\0'){    /* name it */
  594.         strcpy(curbp->b_fname, "pico.save");
  595.         }
  596.         else{
  597.         strcat(curbp->b_fname, ".save");
  598.         }
  599.         writeout(curbp->b_fname);
  600.     }
  601.     vttidy();
  602.     exit(1);
  603.     }
  604. }
  605.  
  606.  
  607. char okinfname[32] = {
  608.       0,    0,             /* ^@ - ^G, ^H - ^O  */
  609.       0,    0,            /* ^P - ^W, ^X - ^_  */
  610.       0,    0x17,        /* SP - ' ,  ( - /   */
  611.       0xff, 0xc0,        /*  0 - 7 ,  8 - ?   */
  612.       0x7f, 0xff,        /*  @ - G ,  H - O   */
  613.       0xff, 0xe1,        /*  P - W ,  X - _   */
  614.       0x7f, 0xff,        /*  ` - g ,  h - o   */
  615.       0xff, 0xe2,        /*  p - w ,  x - DEL */
  616.       0,    0,             /*  > DEL   */
  617.       0,    0,            /*  > DEL   */
  618.       0,    0,             /*  > DEL   */
  619.       0,    0,             /*  > DEL   */
  620.       0,    0             /*  > DEL   */
  621. };
  622.  
  623.  
  624. /*
  625.  * fallowc - returns TRUE if c is allowable in filenames, FALSE otw
  626.  */
  627. fallowc(c)
  628. char c;
  629. {
  630.     return(okinfname[c>>3] & 0x80>>(c&7));
  631. }
  632.  
  633.  
  634.  
  635. /*
  636.  * fexist - returns TRUE if the file exists, FALSE otherwise
  637.  */
  638. fexist(file, m, l)
  639. char *file;
  640. char *m;                    /* files mode: r, w or rw */
  641. long *l;
  642. {
  643.     struct stat    sbuf;
  644.  
  645.     if(l)
  646.       *l = 0L;
  647.  
  648.     if(stat(file, &sbuf) < 0){
  649.     switch(errno){
  650.       case ENOENT :                /* File not found */
  651.         return(FIOFNF);
  652.         break;
  653.       case ENAMETOOLONG :            /* Name is too long */
  654.         return(FIOLNG);
  655.         break;
  656.       default:                /* Some other error */
  657.         return(FIOERR);
  658.         break;
  659.     }
  660.     }
  661.  
  662.     if(l)
  663.       *l = sbuf.st_size;
  664.  
  665.     if(sbuf.st_mode & S_IFDIR)
  666.       return(FIODIR);
  667.  
  668.     if(m[0] == 'r')                /* read access? */
  669.       return(((S_IREAD | 044) & sbuf.st_mode) ? FIOSUC : FIONRD);
  670.     else if(m[0] == 'w')            /* write access? */
  671.       return(((S_IWRITE | 022) & sbuf.st_mode) ? FIOSUC : FIONWT);
  672.     else if(m[0] == 'x')            /* execute access? */
  673.       return(((S_IEXEC | 011) & sbuf.st_mode) ? FIOSUC : FIONEX);
  674.     return(FIOERR);                /* what? */
  675. }
  676.  
  677.  
  678. /*
  679.  * isdir - returns true if fn is a readable directory, false otherwise
  680.  *         silent on errors (we'll let someone else notice the problem;)).
  681.  */
  682. isdir(fn, l)
  683. char *fn;
  684. long *l;
  685. {
  686.     struct stat sbuf;
  687.  
  688.     if(l)
  689.       *l = 0;
  690.  
  691.     if(stat(fn, &sbuf) < 0)
  692.       return(0);
  693.  
  694.     if(l)
  695.       *l = sbuf.st_size;
  696.     return(sbuf.st_mode & S_IFDIR);
  697. }
  698.  
  699.  
  700. #if    defined(nxt) || defined(dyn)
  701. /*
  702.  * getcwd - NeXT uses getwd()
  703.  */
  704. char *getcwd(pth)
  705. char *pth;
  706. {
  707.     extern char *getwd();
  708.  
  709.     return(getwd(pth));
  710. }
  711. #endif
  712.  
  713.  
  714. /*
  715.  * getfnames - return all file names in the given directory in a single 
  716.  *             malloc'd string.  n contains the number of names
  717.  */
  718. char *getfnames(dn, n)
  719. char *dn;
  720. int  *n;
  721. {
  722.     int status;
  723.     long l;
  724.     char *names, *np, *p;
  725.     struct stat sbuf;
  726.     DIR *dirp;                        /* opened directory */
  727. #if    defined(POSIX) || defined(ISC)
  728.     struct dirent *dp;
  729. #else
  730.     struct direct *dp;
  731. #endif
  732.     extern char *sys_errlist[];
  733.  
  734.     *n = 0;
  735.  
  736.     if(stat(dn, &sbuf) < 0){
  737.     switch(errno){
  738.       case ENOENT :                /* File not found */
  739.         emlwrite("\007File not found: \"%s\"", dn);
  740.         break;
  741.       case ENAMETOOLONG :            /* Name is too long */
  742.         emlwrite("\007File name too long: \"%s\"", dn);
  743.         break;
  744.       default:                /* Some other error */
  745.         emlwrite("\007Error getting file info: \"%s\"", dn);
  746.         break;
  747.     }
  748.     return(NULL);
  749.     } 
  750.     else{
  751.     l = sbuf.st_size;
  752.     if(!(sbuf.st_mode & S_IFDIR)){
  753.         emlwrite("\007Not a directory: \"%s\"", dn);
  754.         return(NULL);
  755.     }
  756.     }
  757.  
  758.     if((names=(char *)malloc(sizeof(char)*l)) == NULL){
  759.     emlwrite("\007Can't malloc space for file names");
  760.     return(NULL);
  761.     }
  762.  
  763.     errno = 0;
  764.     if((dirp=opendir(dn)) == NULL){
  765.     sprintf(s,"\007Can't open \"%s\": %s", dn, sys_errlist[errno]);
  766.     emlwrite(s);
  767.     free((char *)names);
  768.     return(NULL);
  769.     }
  770.  
  771.     np = names;
  772.     while((dp = readdir(dirp)) != NULL){
  773.     (*n)++;
  774.     p = dp->d_name;
  775.     while((*np++ = *p++) != '\0')
  776.       ;
  777.     }
  778.  
  779.     closedir(dirp);                    /* shut down */
  780.     return(names);
  781. }
  782.  
  783.  
  784. /*
  785.  * fioperr - given the error number and file name, display error
  786.  */
  787. fioperr(e, f)
  788. int  e;
  789. char *f;
  790. {
  791.     switch(e){
  792.       case FIOFNF:                /* File not found */
  793.     emlwrite("\007File \"%s\" not found", f);
  794.     break;
  795.       case FIOEOF:                /* end of file */
  796.     emlwrite("\007End of file \"%s\" reached", f);
  797.     break;
  798.       case FIOLNG:                /* name too long */
  799.     emlwrite("\007File name \"%s\" too long", f);
  800.     break;
  801.       case FIODIR:                /* file is a directory */
  802.     emlwrite("\007File \"%s\" is a directory", f);
  803.     break;
  804.       case FIONWT:
  805.     emlwrite("\007Write permission denied: %s", f);
  806.     break;
  807.       case FIONRD:
  808.     emlwrite("\007Read permission denied: %s", f);
  809.     break;
  810.       case FIONEX:
  811.     emlwrite("\007Execute permission denied: %s", f);
  812.     break;
  813.       default:
  814.     emlwrite("\007File I/O error: %s", f);
  815.     }
  816. }
  817.  
  818.  
  819.  
  820. /*
  821.  * pfnexpand - pico's function to expand the given file name if there is 
  822.  *           a leading '~'
  823.  */
  824. char *pfnexpand(fn, len)
  825. char *fn;
  826. int  len;
  827. {
  828.     struct passwd *pw;
  829.     struct passwd *getpwnam(), *getpwuid();
  830.     register char *x, *y, *z;
  831.     char name[20];
  832.     
  833.     if(*fn == '~') {
  834.         for(x = fn+1, y = name; *x != '/' && *x != '\0'; *y++ = *x++);
  835.         *y = '\0';
  836.         if(x == fn + 1) 
  837.           pw = getpwuid(getuid());
  838.         else
  839.           pw = getpwnam(name);
  840.         if(pw == NULL)
  841.           return(NULL);
  842.         if(strlen(pw->pw_dir) + strlen(fn) > len) {
  843.             return(NULL);
  844.         }
  845.     /* make room for expanded path */
  846.     for(z=x+strlen(x),y=fn+strlen(x)+strlen(pw->pw_dir);
  847.         z >= x;
  848.         *y-- = *z--);
  849.     /* and insert the expanded address */
  850.     for(x=fn,y=pw->pw_dir; *y != '\0'; *x++ = *y++);
  851.     }
  852.     return(fn);
  853. }
  854.  
  855.  
  856.  
  857. /*
  858.  * fixpath - make the given pathname into an absolute path
  859.  */
  860. fixpath(name, len)
  861. char *name;
  862. int  len;
  863. {
  864.     register char *shft;
  865.  
  866.     if(*name != '/'){                /* filenames relative to ~ */
  867.     if(Pmaster && (*name != '~' && strlen(name)+2 <= len)){
  868.  
  869.         for(shft = strchr(name, '\0'); shft >= name; shft--)
  870.           shft[2] = *shft;
  871.  
  872.         name[0] = '~';
  873.         name[1] = '/';
  874.     }
  875.  
  876.     pfnexpand(name, len);
  877.     }
  878. }
  879.  
  880.  
  881. /*
  882.  * tmpname - return a temporary file name in the given buffer
  883.  */
  884. tmpname(name)
  885. char *name;
  886. {
  887.     sprintf(name, "/tmp/pico.%d", getpid());    /* tmp file name */
  888. }
  889.  
  890.  
  891. /*
  892.  * Take a file name, and from it
  893.  * fabricate a buffer name. This routine knows
  894.  * about the syntax of file names on the target system.
  895.  * I suppose that this information could be put in
  896.  * a better place than a line of code.
  897.  */
  898. makename(bname, fname)
  899. char    bname[];
  900. char    fname[];
  901. {
  902.         register char   *cp1;
  903.         register char   *cp2;
  904.  
  905.         cp1 = &fname[0];
  906.         while (*cp1 != 0)
  907.                 ++cp1;
  908.  
  909.         while (cp1!=&fname[0] && cp1[-1]!='/')
  910.                 --cp1;
  911.         cp2 = &bname[0];
  912.         while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  913.                 *cp2++ = *cp1++;
  914.         *cp2 = 0;
  915. }
  916.  
  917.  
  918.  
  919. /*
  920.  * Open a file for writing. Return TRUE if all is well, and FALSE on error
  921.  * (cannot create).
  922.  */
  923. ffwopen(fn)
  924. char    *fn;
  925. {
  926.         extern FILE *ffp;
  927.  
  928.         if ((ffp=fopen(fn, "w")) == NULL) {
  929.                 emlwrite("Cannot open file for writing");
  930.                 return (FIOERR);
  931.         }
  932.         return (FIOSUC);
  933. }
  934.  
  935.  
  936. /*
  937.  * Close a file. Should look at the status in all systems.
  938.  */
  939. ffclose()
  940. {
  941.         extern FILE *ffp;
  942.  
  943.         if (fclose(ffp) != FALSE) {
  944.                 emlwrite("Error closing file");
  945.                 return(FIOERR);
  946.         }
  947.         return(FIOSUC);
  948. }
  949.  
  950.  
  951. /*
  952.  * P_open - run the given command in a sub-shell returning a file pointer
  953.  *        from which to read the output
  954.  *
  955.  * note:
  956.  *    For OS's other than unix, you will have to rewrite this function.
  957.  *    Hopefully it'll be easy to exec the command into a temporary file, 
  958.  *    and return a file pointer to that opened file or something.
  959.  */
  960. FILE *P_open(s)
  961. char *s;
  962. {
  963.     return(popen(s, "r"));
  964. }
  965.  
  966.  
  967.  
  968. /*
  969.  * P_close - close the given descriptor
  970.  *
  971.  */
  972. P_close(fp)
  973. FILE *fp;
  974. {
  975.     return(pclose(fp));
  976. }
  977.  
  978.  
  979.  
  980. /*
  981.  * worthit - generic sort of test to roughly gage usefulness of using 
  982.  *           optimized scrolling.
  983.  *
  984.  * note:
  985.  *    returns the line on the screen, l, that the dot is currently on
  986.  */
  987. worthit(l)
  988. int *l;
  989. {
  990.     int i;            /* l is current line */
  991.     unsigned below;        /* below is avg # of ch/line under . */
  992.  
  993.     *l = doton(&i, &below);
  994.     below = (i > 0) ? below/(unsigned)i : 0;
  995.  
  996.     return(below > 3);
  997. }
  998.  
  999.  
  1000. /*
  1001.  * pico_new_mail - just checks mtime and atime of mail file and notifies user 
  1002.  *               if it's possible that they have new mail.
  1003.  */
  1004. pico_new_mail()
  1005. {
  1006.     int ret = 0;
  1007.     static time_t lastchk = 0;
  1008.     struct stat sbuf;
  1009.     char   inbox[256];
  1010.  
  1011. #ifdef ISC
  1012.     sprintf(inbox,"/usr/mail/%s", getlogin());
  1013. #else
  1014.     sprintf(inbox,"/usr/spool/mail/%s", getlogin());
  1015. #endif
  1016.     if(stat(inbox, &sbuf) == 0){
  1017.     ret = sbuf.st_atime <= sbuf.st_mtime &&
  1018.       (lastchk < sbuf.st_mtime && lastchk < sbuf.st_atime);
  1019.     lastchk = sbuf.st_mtime;
  1020.     return(ret);
  1021.     }
  1022.     else
  1023.       return(ret);
  1024. }
  1025.  
  1026.  
  1027.  
  1028. /*
  1029.  * time_to_check - checks the current time against the last time called 
  1030.  *                 and returns true if the elapsed time is > timeout
  1031.  */
  1032. time_to_check()
  1033. {
  1034.     static time_t lasttime = 0L;
  1035.  
  1036.     if(!timeout)
  1037.       return(FALSE);
  1038.  
  1039.     if(time((long *) 0) - lasttime > (time_t)timeout){
  1040.     lasttime = time((long *) 0);
  1041.     return(TRUE);
  1042.     }
  1043.     else
  1044.       return(FALSE);
  1045. }
  1046.  
  1047.  
  1048. /*
  1049.  * sstrcasecmp - compare two pointers to strings case independently
  1050.  */
  1051. sstrcasecmp(s1, s2)
  1052. char **s1, **s2;
  1053. {
  1054.     register char *a, *b;
  1055.  
  1056.     a = *s1;
  1057.     b = *s2;
  1058.     while(toupper(*a) == toupper(*b++))
  1059.     if(*a++ == '\0')
  1060.       return(0);
  1061.  
  1062.     return(toupper(*a) - toupper(*--b));
  1063. }
  1064.  
  1065.  
  1066. #ifdef    TIOCGWINSZ
  1067. /*
  1068.  * winch_handler - handle window change signal
  1069.  */
  1070. SIGTYPE winch_handler()
  1071. {
  1072.     struct winsize win;
  1073.     extern int resize_pico();
  1074.  
  1075.     signal(SIGWINCH, (SIGTYPE *)winch_handler);
  1076.  
  1077.     if (ioctl(0, TIOCGWINSZ, &win) == 0) {
  1078.     if (win.ws_col && win.ws_row)
  1079.       resize_pico(win.ws_row - 1, win.ws_col);
  1080.     }
  1081. }
  1082. #endif    /* TIOCGWINSZ */
  1083.